package com.bianguo.android.iocdemo.view.widget;

import android.content.ContentValues;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

import com.bianguo.android.injectlibrary.utils.MLog;
import com.bianguo.android.iocdemo.R;
import com.bianguo.android.iocdemo.bean.DrawPath;
import com.bianguo.android.iocdemo.enums.DrawEnum;
import com.bianguo.android.iocdemo.utils.FileUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

public class DrawBitmapView extends AppCompatImageView implements ScaleGestureDetector.OnScaleGestureListener {

    public static final float MAX_SCALE = 3f;
    public static final float MIN_SCALE = 0.3f;
    private Paint mPaint, mMosaicPaint;
    private float mPreX, mPreY, lastX, lastY;
    private String mFilePath;
    //    private ArrayList<Path> mPaths;
    private ArrayList<DrawPath> mPaths;
    private int mWidth, mHeight;
    private Bitmap mMoasicBitmap;

    private int lineColor, lineWidth;
    private DrawEnum drawType;
    private ScaleGestureDetector scaleGestureDetector;
    private boolean isScale, isTranslate;
    private Matrix mMatrix;
    private float mScaleFactor;
    private float lastDist;
    private float tranTempX, tranTempY;

    public DrawBitmapView(Context context) {
        this(context, null);
    }

    public DrawBitmapView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DrawBitmapView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DrawBitmapView);
        lineColor = typedArray.getColor(R.styleable.DrawBitmapView_line_color, ActivityCompat.getColor(context, R.color.pink));
        lineWidth = typedArray.getColor(R.styleable.DrawBitmapView_line_width, 8);
        typedArray.recycle();

        //禁止硬件加速
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(lineWidth);
        mPaint.setColor(lineColor);
        mPaint.setStrokeJoin(Paint.Join.BEVEL);

        mMosaicPaint = new Paint();
        mMosaicPaint.setAntiAlias(true);
        mMosaicPaint.setStyle(Paint.Style.STROKE);
        mMosaicPaint.setStrokeJoin(Paint.Join.ROUND);
        mMosaicPaint.setStrokeCap(Paint.Cap.ROUND);
        mMosaicPaint.setStrokeWidth(50);

//        mPath = new Path();
        mPaths = new ArrayList<>();
        drawType = DrawEnum.NORMAL_LINE;

        mMatrix = new Matrix();
        mScaleFactor  = 1;
        scaleGestureDetector = new ScaleGestureDetector(context, this);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasure(widthMeasureSpec, 0), getMeasure(heightMeasureSpec, 1));
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
    }

    private int getMeasure(int measureSpec, int type) {
        int result = 0;
        int mode = MeasureSpec.getMode(measureSpec);
        switch (mode) {
            case MeasureSpec.AT_MOST:
                BitmapDrawable drawable = (BitmapDrawable) getDrawable();
                Bitmap bitmap = drawable.getBitmap();
                if (0 == type) {
                    result = bitmap.getWidth();
                } else {
                    result = bitmap.getHeight();
                }
                break;
            case MeasureSpec.EXACTLY:
                result = MeasureSpec.getSize(measureSpec);
                break;
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        BitmapDrawable drawable = (BitmapDrawable) getDrawable();
        if (drawable != null) {
            for (DrawPath mPath : mPaths) {
                int saveLayer = canvas.saveLayer(0, 0, mWidth, mHeight, null, Canvas.ALL_SAVE_FLAG);
                DrawEnum drawType = mPath.getDrawType();
                if (DrawEnum.NORMAL_LINE == drawType) {
                    mPaint.setColor(mPath.getColor());
                    canvas.drawPath(mPath.getPath(), mPaint);
                } else if (DrawEnum.MOSAIC_LINE == drawType) {
                    drawMosaicPath(canvas, drawable.getBitmap(), mPath.getPath(), mMosaicPaint);
                }
                canvas.restoreToCount(saveLayer);
            }
        }
    }

    private void drawMosaicPath(Canvas canvas, Bitmap mBitmap, Path path, Paint mPaint) {
        makeMosaicBitmap(mBitmap);
        canvas.drawPath(path, mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(mMoasicBitmap, 0, 0, mPaint);
        mPaint.setXfermode(null);
    }

    /**
     * 获取马赛克的bitmap
     */
    private Bitmap makeMosaicBitmap(Bitmap mOriginBitmap) {
        if (mMoasicBitmap != null) {
            return mMoasicBitmap;
        }

        int w = Math.round(mWidth / 64f);
        int h = Math.round(mHeight / 64f);

        w = Math.max(w, 8);
        h = Math.max(h, 8);

        if (mOriginBitmap != null) {
            // 先创建小图
            mMoasicBitmap = Bitmap.createScaledBitmap(mOriginBitmap, w, h, false);
            // 再把小图放大
            mMoasicBitmap = Bitmap.createScaledBitmap(mMoasicBitmap, mWidth, mHeight, false);
        }
        return mMoasicBitmap;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                isScale = false;
                mPreX = event.getX();
                mPreY = event.getY();
                lastX = mPreX;
                lastY = mPreY;
                if (mPreX > mWidth / 2 - 100 && mPreX < mWidth / 2 + 100 &&
                mPreY > mHeight / 2 - 100 && mPreY < mHeight / 2 + 100) {
                    isTranslate = true;
                }
                Path mPath = new Path();
                mPath.moveTo(mPreX, mPreY);
                DrawPath drawPath = new DrawPath();
                drawPath.setColor(lineColor);
                drawPath.setPath(mPath);
                drawPath.setDrawType(drawType);
                mPaths.add(drawPath);
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                isScale = true;
                isTranslate = false;
                mPaths.remove(mPaths.size() - 1);
                lastDist = getPointDistance(event);
                break;
            case MotionEvent.ACTION_MOVE:
                if (isScale) {
//                    setScaleEvent(event);
                    float newDist = getPointDistance(event);
                    float scale = newDist / lastDist;
                    scale *= mScaleFactor;
                    if (scale >= MAX_SCALE) {
                        scale = MAX_SCALE;
                    } else if (scale <= MIN_SCALE) {
                        scale = MIN_SCALE;
                    }
                    setScaleX(scale);
                    setScaleY(scale);
                    mScaleFactor = scale;
                } else if (isTranslate) {
                    float tranX = event.getX() - mPreX;
                    float tranY = event.getY() - mPreY;
                    MLog.i("moveX = " + event.getX() + ", moveY = " + event.getY());
                    tranX += tranTempX;
                    tranY += tranTempY;
                    setTranslationX(tranX);
                    setTranslationY(tranY);
                    tranTempX = tranX;
                    tranTempY = tranY;
                } else {
                    int size = mPaths.size();
                    if (size > 0) {
                        float endX = (mPreX + event.getX()) / 2;
                        float endY = (mPreY + event.getY()) / 2;
                        DrawPath path = mPaths.get(size - 1);
                        path.getPath().quadTo(mPreX, mPreY, endX, endY);
                        mPreX = event.getX();
                        mPreY = event.getY();
                    }
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                isScale = false;
                break;
            case MotionEvent.ACTION_UP:
                isScale = false;
                isTranslate = false;
                break;
        }
        invalidate();
        return true;
    }

    private float getPointDistance(MotionEvent event) {
        float distance = 0.0f;
        if (2 == event.getPointerCount()) {
            float distX = Math.abs(event.getX(0) - event.getX(1));
            float distY = Math.abs(event.getY(0) - event.getY(1));
            distance = (float) Math.sqrt(distX * distX + distY * distY);
        }
        return distance;
    }

    private void setScaleEvent(MotionEvent event) {
        if (2 == event.getPointerCount()) {
            scaleGestureDetector.onTouchEvent(event);
        }
    }

    public void reset() {
        int size = mPaths.size();
        if (size > 0) {
            DrawPath mPath = mPaths.get(size - 1);
            mPath.getPath().reset();
            mPaths.remove(mPath);
            postInvalidate();
        }
    }

    public boolean saveToGallery(String fileName, String fileDescription, Bitmap.CompressFormat
            format, int quality) {
        // 控制图片质量
        if (quality < 0 || quality > 100)
            quality = 50;

        long currentTime = System.currentTimeMillis();

        File file = new File(FileUtil.BASE_PATH, FileUtil.TEMP_DIR);
        if (!file.exists()) {
            if (!file.mkdirs()) {
                return false;
            }
        }

        String mimeType = "";
        switch (format) {
            case PNG:
                mimeType = "image/png";
                if (!fileName.endsWith(".png"))
                    fileName += ".png";
                break;
            case WEBP:
                mimeType = "image/webp";
                if (!fileName.endsWith(".webp"))
                    fileName += ".webp";
                break;
            case JPEG:
            default:
                mimeType = "image/jpeg";
                if (!(fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")))
                    fileName += ".jpg";
                break;
        }

        mFilePath = file.getAbsolutePath() + "/" + fileName;
        File f = new File(mFilePath);
        if (f.exists()) {
            f.delete();
        }
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(mFilePath);

            Bitmap b = getChartBitmap();
            b.compress(format, quality, out);

            out.flush();
            out.close();

        } catch (IOException e) {
            e.printStackTrace();

            return false;
        }

        long size = new File(mFilePath).length();

        ContentValues values = new ContentValues(8);

        // store the details
        values.put(MediaStore.Images.Media.TITLE, fileName);
        values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
        values.put(MediaStore.Images.Media.DATE_ADDED, currentTime);
        values.put(MediaStore.Images.Media.MIME_TYPE, mimeType);
        values.put(MediaStore.Images.Media.DESCRIPTION, fileDescription);
        values.put(MediaStore.Images.Media.ORIENTATION, 0);
        values.put(MediaStore.Images.Media.DATA, mFilePath);
        values.put(MediaStore.Images.Media.SIZE, size);

        return getContext().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) != null;
    }

    public Bitmap getChartBitmap() {
        // 创建一个bitmap 根据我们自定义view的大小
        Bitmap returnedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
        // 绑定canvas
        Canvas canvas = new Canvas(returnedBitmap);
        // 获取视图的背景
        Drawable bgDrawable = getBackground();
//        canvas.drawColor(Color.TRANSPARENT);
        if (bgDrawable != null)
            // 如果有就绘制
            bgDrawable.draw(canvas);
        else
            // 没有就绘制白色
            canvas.drawColor(Color.WHITE);
        // 绘制
        draw(canvas);
        return returnedBitmap;
    }

    public void setLineColor(int lineColor) {
        this.lineColor = lineColor;
        mPaint.setColor(lineColor);
    }

    public void setLineWidth(int lineWidth) {
        this.lineWidth = lineWidth;
        mPaint.setStrokeWidth(lineWidth);
    }

    public void setDrawType(DrawEnum type) {
        this.drawType = type;
    }

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        float scaleFactor = detector.getScaleFactor();
        MLog.i("scaleFactor = " + scaleFactor);
        mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
        invalidate();
//        scaleFactor *= mScaleFactor;
//        setScaleX(scaleFactor);
//        setScaleY(scaleFactor);
//        mScaleFactor = scaleFactor;
        return false;
    }

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
        mScaleFactor = detector.getScaleFactor();
    }
}
